package net.wangds.procengine.flow.define;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.wangds.log.helper.LogHelper;
import net.wangds.procengine.ProcResEnum;
import net.wangds.procengine.flow.FlowContext;
import net.wangds.procengine.flow.FlowEngine;
import net.wangds.procengine.flow.FlowOperator;
import net.wangds.procengine.flow.define.actor.ActorDef;
import net.wangds.procengine.flow.define.node.FlowNode;
import net.wangds.procengine.flow.define.node.FlowNodeTypeEnum;
import net.wangds.procengine.flow.define.node.JavaFlowNode;
import net.wangds.procengine.flow.define.node.StartFlowNode;
import net.wangds.procengine.flow.define.node.groovy.GroovyNode;
import net.wangds.procengine.flow.instance.FlowInstance;
import net.wangds.procengine.flow.instance.SimpleFlowInstance;
import net.wangds.procengine.flow.instance.actor.Actor;
import net.wangds.procengine.flow.instance.step.FlowStep;
import net.wangds.procengine.flow.instance.step.SimpleFlowStep;
import net.wangds.procengine.flow.instance.step.groovy.GroovyStep;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;

import java.util.Optional;
import java.util.UUID;
import java.util.function.BiFunction;

/**
 * 简单的流程实现.
 * <p></p>
 *
 * @author 王东石 2020/9/8 17:37.
 */
@NoArgsConstructor
@AllArgsConstructor
public class SimpleFlow<A extends ActorDef> extends AbstractFlowDef<A> implements FlowOperator, InitializingBean {

    /**
     * 流程标识.
     */
    @Getter
    @Setter
    private String flowId;



    @Override
    public <A extends ActorDef> Optional<FlowDef<A>> findFlowDefById(String flowDefId) {
        //LogHelper.dev("查找流程定义:"+flowDefId);
        //如果流程id不一致，返回空
        if(!StringUtils.equals(flowDefId, flowId)){
            // LogHelper.dev("没有找到流程定义:"+flowDefId);
            return Optional.empty();
        }


        AbstractFlowDef<A> res = new AbstractFlowDef<A>() {};

        FlowNode start = new StartFlowNode();
        res.addFlowNode(start);
        // LogHelper.dev("流程定义:"+flowDefId+"的节点数量:"+this.getFlowNodes().size());

        this.getFlowNodes().stream().findFirst().ifPresent(first->start.setNextId(first.getId()));

        this.getFlowNodes().stream().forEach(res::addFlowNode);

        return Optional.of(res);
    }

    @Override
    public <C extends FlowContext, A extends ActorDef> Optional<FlowInstance<C, A>> createFlowInstance(Actor actor, FlowDef<A> def) {
        // LogHelper.info("create flow instance");

        if(def!=this){
            return Optional.empty();
        }

        SimpleFlowInstance<C, A> inst = new SimpleFlowInstance<>();

        inst.setOwner(actor);
        inst.setId(UUID.randomUUID().toString());
        inst.setFlowDefId(def.getId());
        inst.setFlowDef(def);

        return Optional.of(inst);
    }

    @Override
    public <C extends FlowContext, A extends ActorDef> Optional<FlowStep<C>> generateFlowStep(FlowInstance<C,A> instance, FlowNode node, Actor actor) {

        Optional<FlowStep<C>> res = Optional.empty();

        if(node==null){
            return res;
        }

        FlowNodeTypeEnum type = node.getType();

        FlowStep<C> step = null;
        switch(type){
            case START:
                //LogHelper.dev("-------------启动节点："+node.getId());
                SimpleFlowStep<C> tmp = new SimpleFlowStep<C>(){
                    @Override
                    public ProcResEnum proc(C ctx) {
                        //LogHelper.debug("执行开始节点");
                        return ProcResEnum.CONTINUE;
                    }
                };
                tmp.initialize(instance, node, actor);
                step = tmp;
                break;
            case AUTO:
                //LogHelper.dev("-------------自动节点："+node.getId());
                if(node instanceof GroovyNode){
                    GroovyStep<C> groovyStep = new GroovyStep<>();
                    groovyStep.initialize(instance, node, actor);
                    step = groovyStep;
                }else if(node instanceof JavaFlowNode){

                    JavaFlowNode jfNode=(JavaFlowNode)node;
                    BiFunction<FlowContext, Actor, ProcResEnum> func = jfNode.getFunc();

                    step = new SimpleFlowStep<C>(){
                        @Override
                        public ProcResEnum proc(C ctx) {
                            this.setRes(func.apply(ctx, actor));
                            return this.getRes();
                        }
                    };
                }else{
                    LogHelper.debug("目前不支持的自动节点,(仅支持Groovy节点和Java定义的节点)");
                }
                break;
            default:
        }

        if(step!=null){
            res = Optional.of(step);
        }

        return res;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        combine();
        FlowEngine.registorFlowOperator(this);
    }

    /**
     * 构建流程.
     * <p>初始化流程定义.</p>
     */
    protected synchronized void combine(){
            this.getFlowNodes().clear();
    }
}
